package com.example.log.alarm.manager;

import com.example.log.alarm.advice.thread.pool.ThreadPoolWrapper;
import com.example.log.alarm.constant.ThrowableConstant;
import com.example.log.alarm.util.BootstrapSpyUtil;
import com.example.log.alarm.util.WrapperUtil;

import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @program: spring-agent
 * @description:
 * @author: zt22328 赵儒定
 * @create: 2023-05-11 11:01
 **/
public class ThreadPoolManager extends Thread {

    private Map<String, ThreadPoolWrapper> threadPoolWrappers = new ConcurrentHashMap<>();

    public ThreadPoolWrapper getThreadPoolWrapper(ThreadPoolExecutor executor) {
        Optional<ThreadPoolWrapper> first = this.threadPoolWrappers.values().stream().filter(e -> e.executor() == executor).findFirst();
        return first.isPresent() ? first.get() : null;
    }

    private void put(Map<String, Object> map) {
        ThreadPoolWrapper threadPoolWrapper = new ThreadPoolWrapper(map);
        threadPoolWrappers.put(threadPoolWrapper.getThreadPoolId(), threadPoolWrapper);
    }

    public void incrementError(Map<String, Object> map) {
        String threadName = (String) map.get(ThrowableConstant.THREAD_NAME);
        String threadPoolName = WrapperUtil.getThreadPoolName(threadName);
        ThreadPoolWrapper threadPoolWrapper = this.threadPoolWrappers.get(threadPoolName);
        if (threadPoolWrapper == null) {
            return;
        }
        threadPoolWrapper.incrementError();
    }

    public void incrementRejected(Map<String, Object> map) {
        ThreadPoolExecutor executor = (ThreadPoolExecutor) map.get(ThrowableConstant.THREAD_POOL);
        ThreadPoolWrapper threadPoolWrapper = this.getThreadPoolWrapper(executor);
        if (threadPoolWrapper == null) {
            return;
        }
        String threadName = (String) map.get(ThrowableConstant.THREAD_NAME);
        String stackTrace = WrapperUtil.getStackTrace((Exception) map.get(ThrowableConstant.STACK_TRACE));
        threadPoolWrapper.incrementRejected("["+threadName+"]" + stackTrace);
    }

    public void run() {
        while (true) {
            try { Thread.sleep(5000); } catch (InterruptedException e) { }

            for (Map<String, Object> threadPool : BootstrapSpyUtil.getThreadPools(100)) {
                try { put(threadPool); } catch (Exception e) { }
            }

            for (Map<String, Object> rejected : BootstrapSpyUtil.getThreadPoolRejects(5000)) {
                try { incrementRejected(rejected); } catch (Exception e) { }
            }
        }
    }

    public Collection<ThreadPoolWrapper> getThreadPools() {
        return this.threadPoolWrappers.values();
    }

}
